﻿using System;
using System.IO;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using nyxwin.Data.Utils;
using nyxwin.Data.Base;
using nyxwin.Common.Resources;

namespace nyxwin.Data.Session
{
    public sealed class LoginManager
    {
        #region Fields

        internal static Uri ApiUri = new Uri("http://www.nyx.cz/api.php");

        #endregion

        #region Events

        public event EventHandler<LoginEventArgs> LoginCompleted;
        public event EventHandler<ErrorOccurredEventArgs> ErrorOccurred;

        #endregion

        #region Construction
        public LoginManager()
        {
        }
        #endregion

        #region IsAuthorized
        public void IsAuthorized(string authNick, string authToken, Action<LoginEventArgs> action)
        {
            Authorize(authNick, authToken, action);
        }
        #endregion

        #region Authorize

        public void Authorize(string authNick, string authToken)
        {
            Authorize(authNick, authToken, null);
        }

        public void Authorize(string authNick, string authToken, Action<LoginEventArgs> action)
        {
            try
            {
                var request = WebRequest.CreateHttp(ApiUri);

                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.UserAgent = UserDeviceIdentity.UserAgent;

                request.BeginGetRequestStream(
                    delegate(IAsyncResult asyncResultStream)
                    {
                        using (var stream = request.EndGetRequestStream(asyncResultStream))
                        {
                            using (var streamWr = new StreamWriter(stream))
                            {
                                streamWr.Write(string.Format("auth_nick={0}&auth_token={1}&l=help&l2=test", authNick, authToken));
                            }
                        }

                        request.BeginGetResponse(
                            delegate(IAsyncResult asyncResultResponse)
                            {
                                try
                                {
                                    using (var webResponse = request.EndGetResponse(asyncResultResponse))
                                    {
                                        var response = webResponse as HttpWebResponse;

                                        if (response == null)
                                        {
                                            var argz = new LoginEventArgs() { Error = true, ErrorMessage = ErrorResource.ConnectionFailed };
                                            if (action != null) action.Invoke(argz); else FireLoginCompleted(argz);
                                        }
                                        else
                                        {
                                            using (var streamRd = new StreamReader(response.GetResponseStream()))
                                            {
                                                var strData = streamRd.ReadToEnd();
                                                var jsonData = JsonConvert.DeserializeObject(strData) as JObject;
                                                if (jsonData == null)
                                                {
                                                    var argz = new LoginEventArgs() { Error = true, ErrorMessage = ErrorResource.WrongResponseFromServer };
                                                    if (action != null) action.Invoke(argz); else FireLoginCompleted(argz);
                                                }
                                                else
                                                {
                                                    var argz = new LoginEventArgs()
                                                    {
                                                        AuthorizationNick = authNick,
                                                        AuthorizationToken = jsonData.Value<string>("auth_token"),
                                                        AuthorizationCode = jsonData.Value<string>("auth_code"),
                                                        AuthorizationStatus = jsonData.Value<string>("auth_state"),
                                                        AuthorizationComment = jsonData.Value<string>("auth_dev_comment")
                                                    };

                                                    if (action != null) action.Invoke(argz); else FireLoginCompleted(argz);
                                                }
                                            }
                                        }
                                    }
                                }
                                catch (Exception)
                                {
                                    // TODO: Log exception ???
                                    var argz = new LoginEventArgs() { Error = true, ErrorMessage = ErrorResource.ConnectionFailed };
                                    if (action != null) action.Invoke(argz); else FireLoginCompleted(argz);
                                }
                            },
                        null);
                    },
                    null);
            }
            catch (Exception ex)
            {
                FireErrorOccurred(new ErrorOccurredEventArgs(ex));
            }
        }

        #endregion

        #region FireLoginCompleted

        private void FireLoginCompleted(LoginEventArgs e)
        {
            if (null != LoginCompleted)
            {
                LoginCompleted(this, e);
            }
        }

        #endregion

        #region FireErrorOccurred

        private void FireErrorOccurred(ErrorOccurredEventArgs e)
        {
            if (null != ErrorOccurred)
            {
                ErrorOccurred(this, e);
            }
        }

        #endregion
    }
}
